const { values } = require("lodash");

const PENDING = "pending"; //等待状态
const FULFILLED = 'FULFILLED'; //成功状态
const REJECTED = 'rejected'; //失败状态

class MyPromise {
    constructor(executor) {
        //立即调用函数

        try {
            executor(this.resolve, this.reject)
        } catch (reason) {
            this.reject(reason)
        }
    }

    //初始化状态
    status = PENDING
        //初始化成功之后的值
    value = undefined
        //初始化失败之后的值
    reason = undefined
        //用于保存成功回调，成功回调的默认值需要改成数组，因为只有数组可以存储多个回调函数
    valueCallback = []
        //用于保存失败回调，失败回调的默认值需要改成数组，因为只有数组可以存储多个回调函数
    failCallback = []

    resolve = value => {
        //如果状态不是等待 则阻止程序执行
        if (this.status !== PENDING) return
            //把promise状态改为成功
        this.status = FULFILLED
            //保存成功之后的值
        this.value = value
            //如果有这个回调，那么要执行这个回调，并且把成功的值传递进去
            //this.valueCallback && this.valueCallback(this.value);
            //现在呢数组中存储了多个回调函数，所以遍历数组的每个函数并让其执行,上面的代码已经不符合要求
            //重新编写逻辑
            //这里使用while语句用valueCallback.length作为循环条件，如果数组中有值，拿到数组中的第一个回调函数传值并执行
        while (this.valueCallback.length) this.valueCallback.shift()();
    }
    reject = reason => {
        //如果状态不是等待 则阻止程序执行
        if (this.status !== PENDING) return
            //把promise状态改为失败
        this.status = REJECTED
            //保存失败之后的值
        this.reason = reason
            //如果有这个回调,那么要执行这个回调，并且把失败的原因传递进去   
            //this.failCallback && this.failCallback(this.reason);
            //现在呢数组中存储了多个回调函数，所以遍历数组的每个函数并让其执行,上面的代码已经不符合要求
            //重新编写逻辑
            //这里使用while语句用failCallback.length作为循环条件，拿到数组中的第一个回调函数传值并执行
        while (this.failCallback.length) this.failCallback.shift()();

    }
    then(valueCallback, failCallback) {
        valueCallback = valueCallback ? valueCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
            //要实现then方法的链式调用必须创建一promise对象
            //新建一个promise对象
        let promise2 = new MyPromise((resolve, reject) => {
                //逻辑判断如果当前状态为成功 则执行成功的回调并且把保存成功的值传递进去
                if (this.status === FULFILLED) {
                    setTimeout(() => {
                        //捕获成功函数的错误信息
                        try {
                            //保存上一个函数的返回值
                            let x = valueCallback(this.value)
                                //并且把返回值传递给下一个then方法
                                // resolve(x);

                            //判断X的值是普通值还是promise对象

                            //如果是普通值 直接调用resolve

                            //如果是promise对象 查看promise对象返回的结果

                            //再根据promise对象返回的结果 调用resolve还reject 

                            //所有同步代码执行完了才能看到promise2 
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (reason) {
                            //手动调用reject方法 把错误信息传递给下一个promise函数
                            reject(reason)
                        }
                    }, 0);
                    //逻辑判断如果当前状态为成功 则执行失败的回调并且把失败的原因传递进去
                } else if (this.status === REJECTED) {
                    setTimeout(() => {
                        //捕获错误函数的错误信息
                        try {
                            //保存上一个函数的返回值
                            let x = failCallback(this.reason)
                                //并且把返回值传递给下一个then方法
                                // resolve(x);
                                //判断X的值是普通值还是promise对象
                                //如果是普通值 直接调用resolve
                                //如果是promise对象 查看promise对象返回的结果
                                //再根据promise对象返回的结果 调用resolve还reject 
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (reason) {
                            //手动调用reject方法 把错误信息传递给下一个promise函数
                            reject(reason)
                        }


                    }, 0);
                } else {
                    //保存成功回调函数
                    //在这里有一个问题  this.valueCallback一次只能存储一个函数这样的不符合要求
                    //所以在上面定义valueCallback的时候将其定义为数组，这样就可以存储多个回调 ，将回调push进去

                    //重新编辑逻辑
                    this.valueCallback.push(() => {
                        setTimeout(() => {
                            //捕获成功函数的错误信息
                            try {
                                //保存上一个函数的返回值
                                let x = valueCallback(this.value)
                                    //并且把返回值传递给下一个then方法
                                    // resolve(x);

                                //判断X的值是普通值还是promise对象

                                //如果是普通值 直接调用resolve

                                //如果是promise对象 查看promise对象返回的结果

                                //再根据promise对象返回的结果 调用resolve还reject 

                                //所有同步代码执行完了才能看到promise2 
                                resolvePromise(promise2, x, resolve, reject)
                            } catch (reason) {
                                //手动调用reject方法 把错误信息传递给下一个promise函数
                                reject(reason)
                            }


                        }, 0);

                    });
                    //重新编辑逻辑
                    this.failCallback.push(() => {
                        setTimeout(() => {
                            //捕获错误函数的错误信息
                            try {
                                //保存上一个函数的返回值
                                let x = failCallback(this.reason)
                                    //并且把返回值传递给下一个then方法
                                    // resolve(x);

                                //判断X的值是普通值还是promise对象

                                //如果是普通值 直接调用resolve

                                //如果是promise对象 查看promise对象返回的结果

                                //再根据promise对象返回的结果 调用resolve还reject 

                                //所有同步代码执行完了才能看到promise2 
                                resolvePromise(promise2, x, resolve, reject)
                            } catch (reason) {
                                //手动调用reject方法 把错误信息传递给下一个promise函数
                                reject(reason)
                            }


                        }, 0);
                    });
                }
            })
            //返回promise对象
        return promise2
    }
    static all(array) {
        let result = []
        let index = 0
        return new Promise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value
                index++
                if (index == array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    //promise 对象
                    current.then((value) => addData(i, value), reason => reject(reason))
                } else {
                    //普通值
                    addData(i, array[i])
                }
            }

        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
            return value
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    } catch (failCallback) {
        return this.then(undefined, failCallback)
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    //逻辑判断是返回的是当前的promise对象 如果是抛出错误并且阻止程序执行
    if (promise2 === x) {

        return reject(new Typereason('Chaining cycle detected for promise #<Promise>'))

    }
    //逻辑判断如果是promise对象
    if (x instanceof MyPromise) {
        //如果是成功的回调 就把值传递进去 失败的话就把失败的原因传递进去
        //  x.then(value => resolve(value), reason => reject(reason))
        //下面是简写写法
        x.then(resolve, reject)
    } else {
        //逻辑判断是普通值直接传递进去
        resolve(x)
    }

}
module.exports = MyPromise;